#ifndef FORMIC_INPUT_BASE_HEADER
#define FORMIC_INPUT_BASE_HEADER

#include<string>
#include<vector>
#include<map>
#include<complex>

namespace formic {

  // pre-declaration of the archive base class
  class Archive;

  void init_input_commands();

  class InputBase {

    public:

      virtual ~InputBase() {}

      void set_option(const std::string & name, formic::Archive & arch);

      InputBase & operator()(const std::string & name);

      template <class T> const T & get(const std::string & name) const;

      // conversion operators
      operator bool();
      operator int();
      operator long int();
      operator unsigned int();
      operator double();
      operator std::complex<double>();
      operator std::string();
      operator std::vector<int>();
      operator std::vector<long int>();
      operator std::vector<double>();
      operator std::vector<std::complex<double> >();
      operator std::vector<std::string>();

      virtual std::string print_options() = 0;

    protected:

      virtual void initialize_derived() = 0;

      virtual void verify() = 0;

      //virtual void set_next(const std::string & name) = 0;

      //template<class T> void set_member(const std::string & member_name, formic::Archive & arch, T & member);

      // // checks that the conversion is to the type of the most recently asked-for variable
      // // do we really want this?
      // // this will mess up things like:
      // //
      // //   long int x = userinp("name_of_an_int")
      // //
      // // in which normally the int would be promoted to a long int automatically
      // //
      // // ... no, actually it would just return whatever was in _next_long_int unless we set it to throw an error
      // void check_next(const std::string & t) {
      //   if ( t != _type_of_next )
      //     throw formic::Exception("InputBase expected conversion to \"%s\", but \"%s\" was requested instead") % _type_of_next % t;
      //   _type_of_next.clear();
      // }

      std::string _type_of_next;

      bool _next_bool;
      int _next_int;
      long int _next_long_int;
      double _next_double;
      std::complex<double> _next_complex;
      std::string _next_string;
      std::vector<int> _next_vec_int;
      std::vector<long int> _next_vec_long_int;
      std::vector<double> _next_vec_double;
      std::vector<std::complex<double> > _next_vec_complex;
      std::vector<std::string> _next_vec_string;

      std::map<std::string, bool > _bool_map;
      std::map<std::string, int > _int_map;
      std::map<std::string, long int > _long_int_map;
      std::map<std::string, double > _double_map;
      std::map<std::string, std::complex<double> > _complex_map;
      std::map<std::string, std::string > _string_map;
      std::map<std::string, std::vector<int> > _vec_int_map;
      std::map<std::string, std::vector<long int> > _vec_long_int_map;
      std::map<std::string, std::vector<double> > _vec_double_map;
      std::map<std::string, std::vector<std::complex<double> > > _vec_complex_map;
      std::map<std::string, std::vector<std::string> > _vec_string_map;

      //std::set<std::string> _allowed_bool;
      //std::set<std::string> _allowed_int;
      //std::set<std::string> _allowed_long_int;
      //std::set<std::string> _allowed_double;
      //std::set<std::string> _allowed_complex;
      //std::set<std::string> _allowed_string;
      //std::set<std::string> _allowed_vec_int;
      //std::set<std::string> _allowed_vec_long_int;
      //std::set<std::string> _allowed_vec_double;
      //std::set<std::string> _allowed_vec_complex;
      //std::set<std::string> _allowed_vec_string;

  };

}

#endif
